package com.oracle.calllog.analyze.util;

import java.util.List;
import java.util.Map;

import com.oracle.calllog.analyze.model.ContactDimBean;

/**
 * 根据传入的维度数据，得到该数据对应的在表中的主键id
 * ** 做内存缓存，LRUCache
 * 分支
 * -- 缓存中有数据 -> 直接返回id
 * -- 缓存中无数据 ->
 * ** 查询Mysql
 * 分支：
 * -- 数据库中有该条数据 -> 直接返回id -> 将本次读取到的id缓存到内存中
 * -- 数据库中没有该数据  -> 插入该条数据 -> 再次反查该数据，得到id并返回 -> 缓存到内存中
 */
public class ContactAndDateInfoIdUtil {
    //内存缓存对象
    private MyLRUCacheUtil lruCache;
    private DBTool dbTool;

    public ContactAndDateInfoIdUtil(DBTool dbTool) {
    	//构建内存缓存对象
    	lruCache = new MyLRUCacheUtil(3000);
    	this.dbTool = dbTool;
        //此处用于JVM关闭时，释放资源
        //Runtime.getRuntime().addShutdownHook(new Thread(() -> lruCache=null));
    }

    /**
     * 根据传入的维度对象获取对应的主键id。<BR>
     * 处理逻辑为：
     * 	1.如果LRUCache中有则先从LRUCache中获取<BR>
     * 	2.如果没有则从数据库中查询出主键并放在LRUCache中<BR>
     * 	3.如果数据库中也没有则先插入再从数据库中查询出主键 <BR>
     * 时间维度格式：dateinfo_yearmonthday, 10<BR>
     * 联系人维度格式：contact_telephone, 12<BR>
     * @param bean
     * 			维度对象
     * @return
     * 			传入维度对象的主键值
     */
    public int getContactId(ContactDimBean bean) {
        String cacheKey = this.genContactCacheKey(bean);
        //尝试获取缓存的id
        if (lruCache.containsKey(cacheKey)) {
            return lruCache.get(cacheKey);
        }

        //准备对表进行操作，先查询，有可能再插入
        int id = -1;
        synchronized (this) {
            id = this.queryContactId(bean);
        }
        //将刚查询到的id加入到缓存中
        lruCache.put(cacheKey, id);
        return id;
    }


    /**
     * 根据传入的维度对象获取对应的主键id。<BR>
     * 处理逻辑为：
     * 	1.如果LRUCache中有则先从LRUCache中获取<BR>
     * 	2.如果没有则从数据库中查询出主键并放在LRUCache中<BR>
     * 	3.如果数据库中也没有则先插入再从数据库中查询出主键 <BR>
     * 时间维度格式：dateinfo_yearmonthday, 10<BR>
     * 联系人维度格式：contact_telephone, 12<BR>
     * @param bean
     * 			维度对象
     * @return
     * 			传入维度对象的主键值
     */
    public int getDimensionId(ContactDimBean bean) {
        String cacheKey = this.genDimCacheKey(bean);
        //尝试获取缓存的id
        if (lruCache.containsKey(cacheKey)) {
            return lruCache.get(cacheKey);
        }

        //准备对表进行操作，先查询，有可能再插入
        int id = -1;
        synchronized (this) {
            id = this.queryDimensionId(bean);
        }
        //将刚查询到的id加入到缓存中
        lruCache.put(cacheKey, id);
        return id;
    }


    /**
     *	根据传进来的Bean的真正的类型来决定是查询日期表中的主键还是查询联系人表的主键
     * @param bean 对应维度所保存的数据
     * @return
     * 			对应维度的主键数据，出现错误则返回-1
     */
    private int queryDimensionId(ContactDimBean bean) {
        List<Map<String,Object>> results = null;
        //可以优化
        String querySql = "SELECT id FROM tb_dimension_date WHERE year = ? AND month = ? AND day = ?";

        String idLabel = Constants.DB_TYPE.equals("phoenix")?"ID":"id";

        //先查询是否存在此数据，如果存在则直接返回主键
        results = dbTool.queryByPrepared(querySql, bean.getYearDimension(), bean.getMonthDimension(), bean.getDayDimension());
        if(results !=null && results.size()>0) {
            return Integer.valueOf(results.get(0).get(idLabel) + "");
        }else {
            String insertSql = "";
            //如不存在此数据则新增至表中（Phoenix与普通RDBMS的语法不同，分别处理）
            if(Constants.DB_TYPE.equals("phoenix")){
                insertSql = "UPSERT INTO tb_dimension_date (id, year, month, day) VALUES (NEXT VALUE FOR seq_dimension,?, ?, ?)";
                dbTool.updateByPrepared(insertSql, bean.getYearDimension(), bean.getMonthDimension(), bean.getDayDimension());
                //然后再查询此数据并返回主键
                results = dbTool.queryByPrepared("SELECT CURRENT VALUE FOR seq_contacts as ID");
            }else {
                insertSql = "INSERT INTO tb_dimension_date (year, month, day) VALUES (?, ?, ?)";
                dbTool.updateByPrepared(insertSql, bean.getYearDimension(), bean.getMonthDimension(), bean.getDayDimension());
                //然后再查询此数据并返回主键
                results = dbTool.queryByPrepared(querySql, bean.getYearDimension(), bean.getMonthDimension(), bean.getDayDimension());
            }
            return Integer.parseInt(results.get(0).get(idLabel)+"");
        }

    }



    /**
     *	根据传进来的Bean的真正的类型来决定是查询日期表中的主键还是查询联系人表的主键
     * @param bean 对应维度所保存的数据
     * @return
     * 			对应维度的主键数据，出现错误则返回-1
     */
    private int queryContactId(ContactDimBean bean) {
        List<Map<String,Object>> results = null;

        //可以优化
        String querySql = "SELECT id FROM tb_contacts WHERE telephone = ? AND name = ?";
        String idLabel = Constants.DB_TYPE.equals("phoenix")?"ID":"id";
        //先查询是否存在此数据，如果存在则直接返回主键
        results = dbTool.queryByPrepared(querySql, bean.getCallNo(), bean.getCallName());
        if(results !=null && results.size()>0) {
            return Integer.parseInt(results.get(0).get(idLabel)+"");
        }else {
            String insertSql = "";
            //如不存在此数据则新增至表中（Phoenix与普通RDBMS的语法不同，分别处理）
            if(Constants.DB_TYPE.equals("phoenix")){
                insertSql = "UPSERT INTO tb_contacts (id, telephone, name) VALUES (NEXT VALUE FOR seq_contacts, ?, ?)";
                dbTool.updateByPrepared(insertSql,  bean.getCallNo(), bean.getCallName());
                //然后再查询此数据并返回主键
                results = dbTool.queryByPrepared("SELECT CURRENT VALUE FOR seq_contacts as ID");

            }else {
                insertSql = "INSERT INTO tb_contacts (telephone, name) VALUES (?, ?)";
                dbTool.updateByPrepared(insertSql,  bean.getCallNo(), bean.getCallName());
                //然后再查询此数据并返回主键
                results = dbTool.queryByPrepared(querySql,  bean.getCallNo(), bean.getCallName());
            }

            return Integer.parseInt(results.get(0).get(idLabel)+"");
        }
    }

    /**
     * 根据维度信息得到维度对应的缓存键
     *
     * @param bean
     * @return
     */
    private String genContactCacheKey(ContactDimBean bean) {
        String cacheKey = "contact_" + bean.getCallNo();
        return cacheKey;
    }

    /**
     * 根据维度信息得到维度对应的缓存键
     *
     * @param bean
     * @return
     */
    private String genDimCacheKey(ContactDimBean bean) {
        String cacheKey = "dateinfo_" + bean.getYearDimension() + bean.getMonthDimension() + bean.getDayDimension();
        return cacheKey;
    }
}
